function Objective = ecmmvnrobj(Data, Design, Param, Covar, CovarFormat)
%ECMMVNROBJ Log-likelihood for multivariate normal regression with missing data.
% Log-likelihood function based on current maximum likelihood parameter estimates with missing data.
%
%		Objective = ecmmvnrobj(Data, Design, Param, Covar, CovarFormat);
%
% Inputs:
%	Data - NUMSAMPLES x NUMSERIES matrix with NUMSAMPLES samples of a NUMSERIES-dimensional random
%		vector. Missing values are represented as NaNs. Only samples that are entirely NaNs are
%		ignored (to ignore samples with at least one NaN, use MVNRMLE).
%	Design - Either a matrix or a cell-array to handle two distinct model structures. First, if
%		NUMSERIES = 1, Design can be a NUMSAMPLES x NUMPARAMS matrix with known values. This is the
%		"standard" form for regression on a single data series. Alternatively, for any
%		NUMSERIES >= 1, Design can be a cell array of either 1 or NUMSAMPLES cells, where each cell
%		contains a NUMSERIES x NUMPARAMS matrix of known values. If Design has a single cell, then
%		it is assumed to be the same Design matrix for each sample. Otherwise, Design must contain
%		individual Design matrices for each sample.
%	Param - NUMPARAMS x 1 column vector of estimates for the parameters of the regression model.
%	Covar - NUMSERIES x NUMSERIES matrix of estimates for the covariance of the residuals of the
%		regression.
%
% Optional Inputs:
%	CovarFormat - String that specifies the format for the covariance matrix. The choices are:
%		'full' - Default method. Compute the full covariance matrix.
%		'diagonal' - Treat the covariance matrix as a diagonal matrix.
%
% Outputs:
%	Objective - A scalar that contains the log-likelihood of the multivariate normal regression
%		model.
%
% Notes:
%	This function requires Covar to be positive-definite.
%
% See also ECMMVNRMLE, MVNRMLE, MVNROBJ.

%	Copyright 2005-2007 The MathWorks, Inc.
%	$Revision: 1.1.6.2 $ $Date: 2007/05/10 13:44:58 $

if nargin < 5 || isempty(CovarFormat)
	CovarFormat = 'full';
else
	if ~any(strcmpi(CovarFormat,{'full','diagonal'}))
		error('Finance:ecmmvnrobj:InvalidCovarianceFormat', ...
			'Invalid format specified for covariance matrix.');
	end
end
if nargin < 4
	error('Finance:ecmmvnrobj:MissingInputArg', ...
		'Missing required arguments Data, Design, Param, or Covar.');
end

if isempty(Data)
	error('Finance:ecmmvnrobj:EmptyDataArray', ...
		'Empty required input argument Data.');
end
if isempty(Design)
	error('Finance:ecmmvnrobj:EmptyDesignArray', ...
		'Empty required input argument Design.');
end
if isempty(Param)
	error('Finance:ecmmvnrobj:EmptyParam', ...
		'Empty required input argument Param.');
end
if isempty(Covar)
	error('Finance:ecmmvnrobj:EmptyCovar', ...
		'Empty required input argument Covar.');
end

Param = Param(:);

%[NumSamples, NumSeries, NumParams] = checkecmmvnrsetup(Data, Design, Param, Covar);

[NumSamples, NumSeries] = size(Data);
NumParams = size(Param,1);

if iscell(Design) && (numel(Design) == 1)
	SingleDesign = true;
else
	SingleDesign = false;
end

if strcmpi(CovarFormat,'full')
	[CholCovar, CholState] = chol(Covar);
	if CholState > 0
		error('Finance:ecmmvnrobj:NonPosDefCov', ...
			'Covariance is not positive-definite.');
	end

	LogTwoPi = log(2.0 * pi);
	LogDetCovar = 2.0 * sum(log(diag(CholCovar)));

	Count = 0;
	Objective = 0.0;

	for k = 1:NumSamples

		P = ~isnan(Data(k,:));
		Available = sum(P);

		if Available > 0
			Count = Count + 1;

			Objective = Objective - 0.5 * Available * LogTwoPi;

			if iscell(Design)
				if SingleDesign
					Mean = Design{1} * Param;
				else
					Mean = Design{k} * Param;
				end
			else
				Mean = Design(k,:) * Param;
			end

			if Available < NumSeries
				[SubChol, CholState] = chol(Covar(P,P));

				if CholState > 0
					error('Finance:ecmmvnrobj:NonPosDefSubCov', ...
						'Sub-covariance not positive-definite.');
				end

				SubResid = SubChol' \ (Data(k,P)' - Mean(P));

				Objective = Objective - 0.5 * SubResid' * SubResid;
				Objective = Objective - sum(log(diag(SubChol)));
			else
				Resid = CholCovar' \ (Data(k,:)' - Mean);

				Objective = Objective - 0.5 * Resid' * Resid;
				Objective = Objective - 0.5 * LogDetCovar;
			end
		end
	end
else
	InvCovar = diag(1 ./ diag(Covar));
	if sum(any(~isfinite(InvCovar)))
		error('Finance:ecmmvnrobj:NonPosDefCov', ...
			'Covariance is not positive-definite.');
	end
	
	LogTwoPi = log(2.0 * pi);
	LogDetCovar = sum(log(diag(Covar)));
	
	Count = 0;
	Objective = 0.0;

	for k = 1:NumSamples

		P = ~isnan(Data(k,:));
		Available = sum(P);

		if Available > 0
			Count = Count + 1;

			Objective = Objective - 0.5 * Available * LogTwoPi;

			if iscell(Design)
				if SingleDesign
					Mean = Design{1} * Param;
				else
					Mean = Design{k} * Param;
				end
			else
				Mean = Design(k,:) * Param;
			end

			if Available < NumSeries
				SubCovar = Covar(P,P);
				SubInvCovar = diag(1 ./ diag(SubCovar));

				SubResid = Data(k,P)' - Mean(P);

				Objective = Objective - 0.5 * SubResid' * SubInvCovar * SubResid;
				Objective = Objective - 0.5 * sum(log(diag(SubCovar)));
			else
				Resid = Data(k,:)' - Mean;

				Objective = Objective - 0.5 * Resid' * InvCovar * Resid;
				Objective = Objective - 0.5 * LogDetCovar;
			end
		end
	end
end
